home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Scheduling / Cassandra / Source / AddEvent.m < prev    next >
Encoding:
Text File  |  1991-11-01  |  20.9 KB  |  982 lines

  1. //
  2. // AddEvent.m
  3. // Copyright (c) 1989, 1990, 1991 by Jiro Nakamura 
  4. // All rights reserved
  5. //
  6. // Handles the window that allows the user to add events.
  7. // Also is the superclass of EventEdit, which lets the user edit events
  8. //
  9. //    by Jiro Nakamura (jiro@shaman.com)
  10. //
  11. // RCS Information
  12. // Revision Number->    $Revision: 2.15 $
  13. // Last Revised->    $Date: 91/11/01 17:23:32 $
  14. //
  15. char rcsisd[] = "$Id: AddEvent.m,v 2.15 91/11/01 17:23:32 jiro Exp Locker: jiro $";
  16.  
  17. #import "AddEvent.h"
  18. #import "Global.h"
  19. #import "Cassandra.h"
  20. #import "calendar.h"
  21. #import <libc.h>
  22. #import <strings.h>            // for rindex() and strcpy() 
  23. #import <sys/file.h>            // for access()
  24. #import <appkit/Application.h>
  25. #import <appkit/Button.h>
  26. #import <appkit/Form.h>
  27. #import <appkit/Matrix.h>
  28. #import <appkit/Panel.h>               // for NXRunAlertPanel 
  29. #import <appkit/OpenPanel.h>        // for OpenPanel
  30.  
  31.  
  32. #define    RADIO_WEEK    0
  33. #define    RADIO_MON    1
  34. #define    RADIO_MDAY    2
  35. #define    RADIO_YEAR    3
  36. #define    RADIO_HOUR    4
  37. #define    RADIO_MIN    5
  38.  
  39. static char *frequencyChar[4] = {"day","week","month","year"};
  40. static char *alarmExtensions[] = ALARMEXTENSIONS;
  41.  
  42. @implementation AddEvent
  43. - open: sender
  44. {
  45.     ev = [Event newAt: [global eventFile]];
  46.     [self resetDefaultValues : self];
  47.     return self;
  48. }
  49.  
  50. - close
  51. {    
  52.     if( [self isDocEdited] && [self isVisible])
  53.         {        
  54.         #ifdef DEBUG
  55.             fprintf(stderr,"Add/Edit Event window about to close." 
  56.                 "Checking save.\n");
  57.         #endif
  58.     
  59.     
  60.          if (NXRunAlertPanel("Changes not saved",
  61.              "You have made changes to this window. "
  62.             "Do you really want to throw them out?",
  63.             "Dump them","Cancel",NULL) == 0 )
  64.                 return self;
  65.         }
  66.     
  67.     [self setDocEdited: FALSE];
  68.     
  69.     [super close];
  70.     [ev free];
  71.     return self;
  72. }
  73.  
  74.  
  75. - startOver:sender
  76. {
  77.     [self resetDefaultValues: self];
  78.     return self;
  79. }
  80.  
  81. - resetDefaultValues:sender
  82. {
  83.     static struct tm time;
  84.     
  85.     time = *timeNow();
  86.     
  87.     [ev setTime:        &time];
  88.     [ev setSec:        0];
  89.     [ev setSnoozeInt:    0];
  90.     [ev setSnoozeNo:        0];
  91.     [ev setPriority:    50];
  92.     [ev setDestroy:        1];    // Destroy not supported after v0.92
  93.     [ev setAnniversary:    0];
  94.     [ev setMessage:        "Empty Message"];
  95.     [ev setAlarmSound:    [global alarmSound]];
  96.     [ev setPlayAlarm:    [global playAlarm]];
  97.     [ev setShowMessage:    TRUE];
  98.     [self displayValues:    sender];
  99.     
  100.     [self displayValues: self];
  101.         
  102.     [monthForm selectTextAt:0];
  103.     [dateRadioMatrix    selectCellAt: 0: RADIO_MDAY];
  104.     
  105.     return self;
  106. }
  107.  
  108. - displayValues:sender
  109. {
  110.     int temp, temp2;
  111.  
  112.     [self displayDate: self];
  113.     
  114.     if( [ev priority] < 10)
  115.         [priorityRadioMatrix    selectCellAt:    0: 0];
  116.     else 
  117.         {
  118.         if( [ev priority] <= 90)
  119.             [priorityRadioMatrix    selectCellAt: 0:1];
  120.         else
  121.             [priorityRadioMatrix    selectCellAt: 0:2];
  122.         }
  123.     
  124.         
  125.     [messageForm    setStringValue: [ev message]    at:0];
  126.     
  127.     [messageButton    setState:    [ev showMessage]];
  128.     [self message: self];
  129.     
  130.     [alarmSoundForm        setStringValue: [ev alarmSound]    at:0];
  131.     
  132.     switch( [ev alarmAction] )
  133.         {
  134.         case 1:    // playSound
  135.         case 2: // playAndDeleteSound
  136.             [alarmSoundRadioMatrix    selectCellAt: 0 : 0];    
  137.             break;    
  138.         case 3: // runCommand
  139.             [alarmSoundRadioMatrix    selectCellAt: 1 : 0];    
  140.             break;
  141.         
  142.         case 0:    // nothing
  143.         default:
  144.             [alarmSoundRadioMatrix    selectCellAt: 2 : 0];    
  145.             break;
  146.         }
  147.         
  148.  
  149.  
  150.     
  151.     [self sound: self];
  152.     
  153.         
  154.     if( [ev snoozeNo] > 0)
  155.         {
  156.         [snoozeIntForm    setIntValue:     [ev snoozeInt]    at:0];
  157.         [snoozeNoForm    setIntValue:    [ev snoozeNo]    at:0];
  158.         [snoozeButton        setState:     TRUE];
  159.         }
  160.     else
  161.         {
  162.         [snoozeIntForm    setIntValue:     5    at:0];
  163.         [snoozeNoForm    setIntValue:    6    at:0];
  164.         [snoozeButton        setState:    FALSE];
  165.         }
  166.     [self    snooze: self];
  167.  
  168.  
  169.     temp =     [ev anniversary] % 100;
  170.     temp2 =    [ev anniversary] / 100 - 1;
  171.     if( temp2 <= 0)
  172.         temp2 = 0;
  173.                 
  174.     [anniversaryForm     setIntValue: ((temp == 0) ? 1 : temp) at:0];
  175.     [anniversaryRadioMatrix    selectCellAt: 0 : temp2];
  176.     [anniversaryButton    setState:     ( [ev anniversary] > 0)];
  177.                 
  178.     [self anniversary:self];
  179.     [self makeKeyAndOrderFront : self];
  180.     
  181.     // The window is new
  182.     [self setDocEdited:    FALSE];
  183.  
  184.     return self;
  185. }
  186.  
  187.  
  188.  
  189. - displayDate: sender
  190. {
  191.     int temp;
  192.     char min[5];
  193.     extern const char *shortMonths[12];
  194.     
  195.     if( [global militaryTime])
  196.         {
  197.         [hourForm    setIntValue:    [ev hour]];
  198.         [amPmButton    setEnabled: FALSE];
  199.         [amPmButton     setState:    AM];
  200.         }
  201.     else
  202.         {
  203.         temp = [ev hour];
  204.         if( temp > 12 )
  205.             temp -= 12;
  206.         if( temp == 0 )
  207.             temp = 12;
  208.         [hourForm     setIntValue:     temp       at:0];
  209.         [amPmButton    setEnabled:    TRUE];
  210.         if( [ev hour] >= 12)
  211.             [amPmButton     setState: PM];
  212.         else
  213.             [amPmButton     setState: AM];
  214.         }
  215.         
  216.     sprintf(min,"%02d",[ev min]);
  217.     [minuteForm     setStringValue: min    at:0];
  218.     [dayForm     setIntValue:     [ev mday]    at:0];
  219.     [monthForm     setStringValue: shortMonths[([ev mon])]
  220.                  at:    0];    
  221.     [yearForm     setIntValue     : ([ev year]+ 1900)    at:0];
  222.     [self updateTestDate : [ev time]];
  223.     return self;
  224. }
  225.  
  226. - dateUp: sender
  227. {
  228.     struct tm *displayTime;
  229.  
  230.     if( (displayTime = [self getDate: self]) == NULL)
  231.         return self;
  232.     
  233.     switch( [dateRadioMatrix selectedCol])
  234.         {
  235.         case RADIO_WEEK:
  236.             displayTime->tm_mday += 7;
  237.             break;
  238.         case RADIO_MON:
  239.             displayTime->tm_mon ++;
  240.             break;
  241.         case RADIO_MDAY:
  242.             displayTime->tm_mday ++;
  243.             break;
  244.         case RADIO_YEAR:
  245.             displayTime->tm_year ++;
  246.             break;
  247.         case RADIO_HOUR:
  248.             displayTime->tm_hour ++;
  249.             break;
  250.         case RADIO_MIN:
  251.             displayTime->tm_min ++;
  252.             break;
  253.         }
  254.  
  255.     fixTmStructure( displayTime);
  256.     [ev setTime: displayTime];
  257.     [self displayDate: self];
  258.     [self setDocEdited:    TRUE];
  259.     return self;
  260. }
  261.  
  262. - dateDown: sender
  263. {
  264.     struct tm *displayTime;
  265.  
  266.     if( (displayTime = [self getDate: self]) == NULL)
  267.         return self;
  268.     
  269.     switch( [dateRadioMatrix selectedCol])
  270.         {
  271.         case RADIO_WEEK:
  272.             displayTime->tm_mday -= 7;
  273.             break;
  274.         case RADIO_MON:
  275.             displayTime->tm_mon --;
  276.             break;
  277.         case RADIO_MDAY:
  278.             displayTime->tm_mday --;
  279.             break;
  280.         case RADIO_YEAR:
  281.             displayTime->tm_year --;
  282.             break;
  283.         case RADIO_HOUR:
  284.             displayTime->tm_hour --;
  285.             break;
  286.         case RADIO_MIN:
  287.             displayTime->tm_min --;
  288.             break;
  289.         }
  290.  
  291.     fixTmStructure( displayTime);
  292.     [ev setTime: displayTime];
  293.     [self displayDate: self];
  294.     [self setDocEdited:    TRUE];
  295.     return self;
  296. }
  297.             
  298.             
  299. - anniversary:sender
  300. {
  301.     BOOL aFlag;
  302.     
  303.     #ifdef DEBUG
  304.         fprintf(stderr,"Anniversary button pressed. State = %d\n",
  305.             [anniversaryButton state]);
  306.     #endif
  307.  
  308.     aFlag = [anniversaryButton state];
  309.     
  310.     [anniversaryRadioMatrix    setEnabled: aFlag];
  311.     [anniversaryForm    setEnabled: aFlag];
  312.     [everyTextField        setEnabled: aFlag];
  313.     [anniversaryUpButton    setEnabled: aFlag];
  314.     [anniversaryUpButton    setIcon:
  315.         (aFlag?RIGHTARROW:DISABLEDRIGHTARROW)];
  316.     [anniversaryDownButton    setEnabled: aFlag];
  317.     [anniversaryDownButton    setIcon:
  318.         (aFlag?LEFTARROW:DISABLEDLEFTARROW)];
  319.             
  320.     if( aFlag )
  321.         [anniversaryForm    selectTextAt: 0];
  322.             
  323.     [self    anniversaryFinished: self];
  324.         return self;
  325. }
  326.  
  327. - anniversaryUp: sender
  328. {
  329.     [anniversaryForm    setIntValue: 
  330.         ([anniversaryForm intValueAt:0] +1) at:0];
  331.     [self anniversaryFinished: self];
  332.     return self;
  333. }
  334.  
  335. - anniversaryDown: sender
  336. {
  337.     int temp;
  338.  
  339.     temp = [anniversaryForm    intValueAt: 0] - 1;
  340.     
  341.     if( temp > 1)
  342.         [anniversaryForm    setIntValue: temp at:0];
  343.     else
  344.         [anniversaryForm    setIntValue: 1 at:0];
  345.         
  346.     [self anniversaryFinished: self];    
  347.     return self;
  348. }
  349.  
  350.  
  351. - snooze: sender
  352. {
  353.     BOOL aFlag;        // the state of the snooze button
  354.  
  355.     #ifdef DEBUG
  356.         fprintf(stderr,
  357.             "Snooze button pressed. State = %d\n",
  358.             [snoozeButton state]);
  359.     #endif
  360.     
  361.     aFlag = [snoozeButton state];
  362.     
  363.     [snoozeNoForm        setEnabled: aFlag];
  364.     [snoozeIntForm        setEnabled: aFlag];
  365.     [snoozeTimesTextField    setEnabled: aFlag];
  366.     [snoozeMinutesTextField    setEnabled: aFlag];
  367.     
  368.     [snoozeIntUpButton    setEnabled: aFlag];
  369.     [snoozeIntUpButton    setIcon:
  370.         aFlag?RIGHTARROW:DISABLEDRIGHTARROW];
  371.     [snoozeIntDownButton    setEnabled: aFlag];
  372.     [snoozeIntDownButton    setIcon:
  373.         aFlag?LEFTARROW:DISABLEDLEFTARROW];
  374.     [snoozeNoUpButton    setEnabled: aFlag];
  375.     [snoozeNoUpButton    setIcon:
  376.         aFlag?RIGHTARROW:DISABLEDRIGHTARROW];
  377.     [snoozeNoDownButton    setEnabled: aFlag];
  378.     [snoozeNoDownButton    setIcon:
  379.         aFlag?LEFTARROW:DISABLEDLEFTARROW];
  380.     
  381.     if( aFlag )
  382.         [snoozeIntForm    selectTextAt:0];
  383.             
  384.     [self snoozeFinished: self];
  385.     return self;
  386. }
  387.  
  388. - snoozeIntUp: sender
  389. {
  390.     [snoozeIntForm    setIntValue: 
  391.         ([snoozeIntForm    intValueAt: 0] + 1) at:0];
  392.     [self snoozeFinished: self];
  393.     return self;
  394.  
  395. }
  396.  
  397. - snoozeIntDown: sender
  398. {
  399.     int temp;
  400.  
  401.     temp = [snoozeIntForm    intValueAt: 0] - 1;
  402.     if( temp > 1)
  403.         [snoozeIntForm    setIntValue: temp at:0];
  404.     else
  405.         [snoozeIntForm    setIntValue: 1 at:0];
  406.     
  407.     [self snoozeFinished: self];
  408.     return self;
  409. }
  410.  
  411. - snoozeNoUp: sender
  412. {
  413.     [snoozeNoForm    setIntValue: 
  414.         ([snoozeNoForm    intValueAt: 0] + 1) at:0];
  415.     [self snoozeFinished: self];
  416.     return self;
  417. }
  418.  
  419. - snoozeNoDown: sender
  420. {
  421.     int temp;
  422.  
  423.     temp = [snoozeNoForm    intValueAt: 0] - 1;
  424.     if( temp > 1)
  425.         [snoozeNoForm    setIntValue: temp at:0];
  426.     else
  427.         [snoozeNoForm    setIntValue: 1 at:0];
  428.     
  429.     [self snoozeFinished: self];
  430.     return self;
  431. }
  432.  
  433. - snoozeFinished: sender
  434. {
  435.     static char buf[50];
  436.     int sInt, sNo;
  437.  
  438.     // The window has changed
  439.     [self setDocEdited:    TRUE];
  440.  
  441.     if( [snoozeButton state])
  442.         {
  443.         sInt = [snoozeIntForm    intValueAt: 0];
  444.         sNo  = [snoozeNoForm    intValueAt: 0];
  445.         
  446.         sprintf(buf, "time%s",(sNo == 1)?"":"s");
  447.         [snoozeTimesTextField    setStringValue: buf];
  448.         
  449.         sprintf(buf, "minute%s",(sInt == 1)?"":"s");
  450.         [snoozeMinutesTextField    setStringValue: buf];
  451.             
  452.         sprintf(buf,"Snooze alarm set every %d minute%s "
  453.             "for the next %d minute%s.",
  454.             sInt,
  455.             (sInt == 1)?"":"s",
  456.             (sInt * sNo),
  457.             ((sInt * sNo)  == 1)?"":"s"
  458.             );
  459.         [testSnoozeTextField setStringValue: buf];
  460.         }
  461.     else
  462.         [testSnoozeTextField setStringValue:
  463.             "The snooze function is not enabled."];
  464.  
  465.     [self selectNextText: sender];
  466.     return self;
  467. }
  468.  
  469.  
  470. - message: sender
  471. {
  472.     [messageForm    setEnabled:    [messageButton    state]];
  473.     return self;
  474. }
  475.  
  476. - messageFinished: sender
  477. {
  478.     // The window has changed
  479.     [self setDocEdited:    TRUE];
  480.     return self;
  481. }
  482.  
  483.  
  484. - sound: sender
  485. {
  486.     int mode;        // state of alarmSound matrix
  487.  
  488.     mode = [alarmSoundRadioMatrix selectedRow];
  489.     
  490.     [alarmSoundForm    setEnabled:    mode != 2];
  491.     [playButton    setEnabled:    mode == 0];
  492.     [setButton    setEnabled:    mode == 0];
  493.     [stopButton    setEnabled:    FALSE];
  494.     
  495.     if( mode !=2)
  496.         [alarmSoundForm    selectTextAt: 0];
  497.     return self;
  498. }
  499.  
  500. - soundFinished: sender
  501. {
  502.     // The window has changed
  503.     [self setDocEdited:    TRUE];
  504.  
  505.     if( [alarmSoundRadioMatrix selectedRow] == 0)
  506.         [self checkSound: self];
  507.     return self;
  508. }
  509.  
  510. - playSound:sender
  511. {
  512.     int error;
  513.     
  514.     // If we are given a path name for an alarm sound, use the pathname
  515.     // in newFromSoundFile. Otherwise, we will have to go look for it
  516.     // using findSoundFor.
  517.     if( index((char *) [alarmSoundForm stringValueAt:0], '/') 
  518.                 == (char *) 0)
  519.         soundfile = [Sound findSoundFor:  
  520.             (char *) [alarmSoundForm stringValueAt:0]];
  521.     else
  522.         soundfile = [Sound newFromSoundfile: 
  523.             (char *) [alarmSoundForm stringValueAt:0]];
  524.         
  525.     if( soundfile != nil)
  526.             {
  527.             [soundfile setDelegate: self];
  528.             // From 1.0 Docs, Sound Kit, pp22-498
  529.             [Sound getVolume: &oldVolumeLeft:&oldVolumeRight];
  530.             if( [global volume] >= 0)
  531.                 [Sound setVolume: [global volume]
  532.                         : [global volume]];
  533.  
  534.             error = [soundfile play];
  535.             if( error == 0)
  536.                 {
  537.                 [stopButton     setEnabled    : TRUE];
  538.                 [playButton     setEnabled    : TRUE];
  539.                  }
  540.             else
  541.                 {
  542.                 char errorString[200];
  543.                 // Restore old volume
  544.                 [Sound    setVolume: oldVolumeLeft:
  545.                          oldVolumeRight];
  546.  
  547.                 sprintf(errorString,
  548.                     "Error #%d (%s) occured while "
  549.                     "trying to play the sound <%s>.\n", 
  550.                     error, SNDSoundError(error),
  551.                     [alarmSoundForm stringValueAt:0]);
  552.                     
  553.                 NXRunAlertPanel("Alarm Error",errorString, 
  554.                         "Oh well...",NULL,NULL);
  555.                 }
  556.             }
  557.         else
  558.             {
  559.             NXRunAlertPanel("Sound not found",
  560.                 "I couldn't find that sound.", 
  561.                 "Oh well...",NULL,NULL);
  562.             [alarmSoundForm    selectText:self];
  563.             }
  564.     
  565.     return self;
  566. }
  567.  
  568. - checkSound:sender
  569. {
  570.  
  571.     if( [alarmSoundRadioMatrix selectedRow] != 0 )
  572.         {
  573.         [self selectNextText:sender];
  574.         return self;
  575.         }
  576.         
  577.         
  578.     if(     ([Sound findSoundFor:  
  579.             (char *) [alarmSoundForm stringValueAt:0]] == nil)  &&
  580.         ( access( [alarmSoundForm stringValueAt:0], R_OK) == -1))
  581.         {
  582.         NXRunAlertPanel("Sound not found",
  583.                 "I couldn't find that sound. "
  584.                 "Please double check.",
  585.                 "OK",NULL,NULL);
  586.         [alarmSoundForm    selectText:self];
  587.         }
  588.     else
  589.         [self selectNextText:sender];
  590.     return self;
  591. }
  592.  
  593.  
  594. - stopSound:sender
  595. {
  596.     [soundfile stop];
  597.         return self;
  598. }
  599.  
  600. - willPlay : sender
  601. {
  602.     #ifdef DEBUG
  603.         fprintf(stderr,"Alarm sound starting.\n");
  604.     #endif
  605.     
  606.     [playButton setEnabled: FALSE];
  607.     return self;
  608. }
  609.  
  610. - hadError: sender
  611. {
  612.     char errorString[200];
  613.     int error = [[sender soundBeingProcessed] processingError];    
  614.     
  615.     sprintf(errorString,
  616.         "Error #%d (%s) occured while playing the sound <%s>.\n", 
  617.         error, SNDSoundError(error),
  618.         [alarmSoundForm stringValueAt:0]);
  619.                     
  620.     NXRunAlertPanel("Alarm Error",errorString, 
  621.             "Oh well...",NULL,NULL);
  622.         
  623.     [stopButton setEnabled: FALSE];
  624.     if( [alarmSoundRadioMatrix selectedRow] == 0)
  625.         [playButton    setEnabled:    TRUE];
  626.     else
  627.         [playButton    setEnabled:    FALSE];
  628.         
  629.     // Restore old volume
  630.     [Sound    setVolume: oldVolumeLeft: oldVolumeRight];
  631.     return self;
  632. }
  633.  
  634. - didPlay:sender
  635. {
  636.     [soundfile free];
  637.     [stopButton setEnabled: FALSE];
  638.         
  639.     if( [alarmSoundRadioMatrix selectedRow] == 0)
  640.         [playButton    setEnabled:    TRUE];
  641.     else
  642.         [playButton    setEnabled:    FALSE];
  643.  
  644.     // Restore old volume
  645.     [Sound    setVolume: oldVolumeLeft: oldVolumeRight];
  646.     
  647.     return self;
  648. }
  649.  
  650.  
  651. - insertEventAndClose: sender
  652. {
  653.     #ifdef DEBUG
  654.         fprintf(stderr,"InsertEventAndClose: %x is the flag.\n",
  655.             [NXApp currentEvent]->flags);
  656.     #endif
  657.     
  658.     if( [self insertEvent:self] == nil)        // user aborted
  659.         return self;
  660.     
  661.     if( !( ([NXApp currentEvent]->flags) & NX_ALTERNATEMASK))    
  662.         [self close];
  663.     [cassandra queueDidChange:self];
  664.     return self;
  665. }
  666.     
  667. - insertEvent:sender
  668. {
  669.     struct tm time, *timePointer;
  670.     int vAnniv;
  671.     
  672.     time = *timeNow();
  673.     
  674.     [ev setMessage:        (char *) [messageForm     stringValueAt:0]];
  675.     [ev setShowMessage:    [messageButton        state]];
  676.     switch( [alarmSoundRadioMatrix selectedRow] )
  677.         {
  678.         case 0:    // sound
  679.             [ev setAlarmAction: 1];
  680.             break;
  681.         case 1: // runCommand
  682.             [ev setAlarmAction: 3];
  683.             break;
  684.         case 2: // nada
  685.             [ev setAlarmAction: 0];
  686.         break;
  687.         }
  688.  
  689.     [ev setAlarmSound:    (char *) [alarmSoundForm stringValueAt:0]];
  690.  
  691.     if( (timePointer = [self getDate: self]) == NULL)
  692.         return nil;
  693.      
  694.     [ev setTime:    timePointer];
  695.     
  696.     if( [anniversaryForm intValueAt:0] > 99)
  697.         {
  698.         NXRunAlertPanel("Anniversary Overload",
  699.             "Due to a design error that cannot be fixed "
  700.             "until a future version, you cannot have a reoccuring "
  701.             "event of more than 99 intervals.","OK",NULL,NULL);
  702.         [anniversaryForm selectTextAt: 0];
  703.         return nil;
  704.         }
  705.     vAnniv = ([anniversaryRadioMatrix selectedCol] +1 ) * 100;    
  706.     [ev setAnniversary:     ([anniversaryButton state] 
  707.                 ? ([anniversaryForm intValueAt:0] + vAnniv)    
  708.                 : 0) ];
  709.     
  710.     [ev setDestroy:        1];    // Destroy not supported after v0.9.2
  711.     
  712.     [ev setSnoozeNo:        ([snoozeButton state]
  713.                 ?[snoozeNoForm intValueAt:0]
  714.                 :0)];
  715.     [ev setSnoozeInt:     ([snoozeButton state]
  716.                 ?[snoozeIntForm intValueAt:0]
  717.                 :0)];
  718.     [ev setPriority:     [priorityRadioMatrix selectedCol]*50];
  719.     
  720.     // If the user tries to put in an event with a date that has     
  721.     // already past, inform them of the problem */
  722.     if(  timeCompare(  [ev time], &time ) == -1)
  723.         if(  NXRunAlertPanel("Insert Warning",
  724.             "The date you have typed in has already passed. "
  725.             "Are you sure you want to insert it?",
  726.             "Insert","Cancel",NULL) == 0)
  727.             return nil;
  728.         
  729.     [ev insertEvent];
  730.  
  731.     // The window has been saved
  732.     [self setDocEdited:    FALSE];
  733.  
  734.     return self;
  735. }
  736.  
  737.  
  738. - setSound:sender
  739. {
  740.     OpenPanel *myOpenPanel;
  741.     char tempDir[128], *tempFile;
  742.  
  743.     myOpenPanel = [OpenPanel new];
  744.     
  745.     if( index([ev alarmSound], '/') == (char *) 0)    // If the present isn't
  746.         [ev setAlarmSound: ALARMSOUND];        // a path to a sound
  747.         
  748.     strcpy(tempDir, [ev alarmSound]);
  749.     tempFile = rindex(tempDir,'/') + 1;
  750.     *(rindex (tempDir,'/')) = '\0';
  751.  
  752.     #ifdef DEBUG
  753.         fprintf(stderr,"Open directory <%s> with file <%s>\n",
  754.                  tempDir, tempFile);
  755.     #endif
  756.     
  757.     if( [myOpenPanel runModalForDirectory:    tempDir
  758.         file:    tempFile types:  alarmExtensions ] == 0)
  759.         return self;
  760.  
  761.     #ifdef DEBUG
  762.         fprintf(stderr,"Opening file <%s>\n", [myOpenPanel filename]);
  763.     #endif
  764.             
  765.     [ev setAlarmSound: (char *) [myOpenPanel filename]];
  766.     [alarmSoundForm    setStringValue:    [ev alarmSound]    at: 0];
  767.     return self;
  768. }
  769.  
  770. - setCassandra: anObject
  771. {
  772.     cassandra = anObject;
  773.     return self;
  774. }
  775.  
  776.  
  777. - anniversaryFinished: sender
  778. {
  779.     int radioCol, temp;
  780.     static char buf1[10], buf2[80];
  781.  
  782.     // The window has changed
  783.     [self setDocEdited:    TRUE];
  784.     
  785.     radioCol =     [anniversaryRadioMatrix selectedCol];
  786.     temp =         [anniversaryForm intValueAt:0];
  787.     sprintf(buf1, "%s%c", frequencyChar[radioCol], (temp != 1)?'s':'\0');
  788.     [everyTextField setStringValue: buf1];
  789.     
  790.     if( [anniversaryButton state])
  791.         {
  792.         if( temp == 1)
  793.             sprintf(buf2,"I will remind you every %s.",
  794.                 frequencyChar[radioCol]);
  795.         else
  796.             sprintf(buf2,"I will remind you every %d %s.",
  797.                 [anniversaryForm intValueAt:0],
  798.                 buf1);
  799.         [testAnniversaryTextField setStringValue: buf2];
  800.         }
  801.     else
  802.         [testAnniversaryTextField setStringValue:
  803.             "This is not a reoccuring event."];
  804.     return self;
  805. }
  806.  
  807. - updateTestDate : (struct tm *) tnow
  808. {
  809.     static char buf[5];
  810.     extern const char *shortWeekDays[7];
  811.     
  812.     [testDateTextField setStringValue:  
  813.         ascMyTime( tnow, NOSEC, [global militaryTime])];
  814.     
  815.     sprintf(buf,"%s", shortWeekDays[tnow->tm_wday]);
  816.     [wdayTextField    setStringValue: buf ];
  817.  
  818.     return self;
  819. }
  820.  
  821. // Slight workaround for IB, since IB only likes values 
  822. // that return (id), but I need the (struct tm *) in another 
  823. // part of the program, so all we do is message getDate
  824. // and ignore the return value.
  825. - dateFinished: sender
  826. {
  827.     // The window has changed
  828.     [self setDocEdited:    TRUE];
  829.  
  830.     [self getDate:sender];
  831.     return self;
  832. }
  833.  
  834. - (struct tm*) getDate :  (id) sender
  835. {
  836.     static struct tm eventTime;
  837.     int month, year;
  838.     static char buf[100];
  839.     extern const char *shortMonths[12];
  840.         
  841.     eventTime.tm_sec = 0;
  842.     
  843.     // Get the hour form and make sure it is in good shape
  844.     strcpy(buf, [hourForm stringValueAt:0]);
  845.     eventTime.tm_hour = atoi(buf);
  846.     if( ![global militaryTime])    // if we are not using 24hr time
  847.         {
  848.         // then let's check for am/pm suffix
  849.         if( rindex( buf, 'a') || rindex(buf, 'A') || 
  850.             rindex(buf, 'n') || rindex(buf, 'N'))
  851.             [amPmButton setState: AM];        
  852.         else if (rindex(buf, 'p') || rindex(buf,'P') ||
  853.             rindex(buf, 'm') || rindex(buf, 'M'))
  854.             [amPmButton setState: PM];
  855.         }
  856.         
  857.     if( [global militaryTime])
  858.         {
  859.         if( eventTime.tm_hour < 0 || eventTime.tm_hour > 23)
  860.             {
  861.             NXRunAlertPanel( "Time error",
  862.                     "I had trouble reading the hour "
  863.                     "of the event. "
  864.                     "We are using military time. "
  865.                     "Please type in a number from "
  866.                     "0-23 in the hour form.",
  867.                     "OK",NULL,NULL);
  868.             [hourForm selectTextAt:0];
  869.             return NULL;
  870.             }
  871.         }
  872.     else
  873.         {
  874.         if( eventTime.tm_hour < 1 || eventTime.tm_hour > 12)
  875.             {
  876.             NXRunAlertPanel( "Time error",
  877.                     "I had trouble reading the hour "
  878.                     "of the event. "
  879.                     "We are using am/pm time. "
  880.                     "Please type in a number from 1-12 "
  881.                     "in the hour form.",
  882.                     "OK",NULL,NULL);
  883.             [hourForm selectTextAt:0];
  884.             return NULL;
  885.             }
  886.  
  887.         if(eventTime.tm_hour == 12)
  888.             eventTime.tm_hour = 0;
  889.         eventTime.tm_hour += ( ([amPmButton state] == AM) ? 0 : 12);    
  890.         }
  891.     
  892.     // Get the minutes, check their format
  893.     eventTime.tm_min =  [minuteForm intValueAt:0];
  894.     if( eventTime.tm_min < 0 || eventTime.tm_min > 59)
  895.         {
  896.         NXRunAlertPanel( "Time error",
  897.                 "I had trouble reading the minute "
  898.                 "of the event. "
  899.                 "Please type in a number from 0-59 "
  900.                 "in the minute form.",
  901.                 "OK",NULL,NULL);
  902.         [minuteForm selectTextAt:0];
  903.         return NULL;
  904.         }
  905.         
  906.     
  907.     if(  (month = monthFromAscii((char*) [monthForm stringValueAt:0]))  == 0)
  908.         {
  909.         [monthForm selectTextAt:0];
  910.         return NULL;    // If the month is in an incorrect format return
  911.         }
  912.     eventTime.tm_mon =  ( month - 1);
  913.     
  914.     
  915.     // Get the year and check its format
  916.     year = [yearForm intValueAt:0];
  917.     if( year < 0 || year > 3000)
  918.         {
  919.         NXRunAlertPanel( "Time error",
  920.                 "I had trouble reading the year of the event. "
  921.                 "Please type in a number from 0-3000 in the "
  922.                 "year form. See the manual or online help "
  923.                 "for abbreviations.",
  924.                 "OK",NULL,NULL);
  925.         [yearForm selectTextAt:0];
  926.         return NULL;
  927.         }
  928.     if( year < 70)    
  929.         eventTime.tm_year =  100+ year;
  930.     if( year >= 70 && year < 100)
  931.         eventTime.tm_year =  year;
  932.     if( year >= 100)
  933.         eventTime.tm_year = year - 1900;
  934.     
  935.         
  936.     // Get the day, check its form
  937.     eventTime.tm_mday =   [dayForm intValueAt:0];
  938.     if( eventTime.tm_mday < 1 || eventTime.tm_mday > 31)
  939.         {
  940.         sprintf( buf, "I had trouble reading the day of the event. "
  941.                 "Please type in a number from 1-31 in the "
  942.                 "day form. (Hint: %s. %4d has %d days)", 
  943.             shortMonths[eventTime.tm_mon], 
  944.             eventTime.tm_year + 1900, 
  945.             daysInMonth( eventTime.tm_mon + 1, 
  946.                     eventTime.tm_year + 1900));
  947.         NXRunAlertPanel( "Time error",buf,"OK",NULL,NULL);
  948.         [dayForm selectTextAt:0];
  949.         return NULL;
  950.         }
  951.         
  952.     
  953.     fixTmStructure( &eventTime);
  954.     [self updateTestDate: &eventTime];
  955.     [self selectNextText:sender];
  956.     
  957.     return ( &eventTime);
  958. }
  959.  
  960. - selectNextText:sender
  961. {
  962.     // If the sender is a form class or a subclass of it, then 
  963.     // we want the nextText private variable of the sender, 
  964.     // to use to select the next Form after the user hits return 
  965.     // but NeXT programmers haven't given us a method to access it 
  966.     // so we take it by brute force (I know, I know.... breaking data 
  967.     // abstractions...) 
  968.     // This is out of Cox, "Object Orientated Programming, pp.147 
  969.     
  970.  
  971.     if( [sender isKindOf:     [Form class] ] )
  972.         {
  973.         struct idform {@defs(Form);} *p = (struct idform *)sender;
  974.         [p->nextText selectText:self];
  975.         }
  976.     return self;
  977. }
  978.  
  979.  
  980.  
  981. @end
  982.